const nbObjects = 800;
var conf, scene, camera, cameraCtrl, light, renderer;
var whw, whh;

var objects;
var spriteMap, spriteMaterial;

var mouse = new THREE.Vector2();
var mouseOver = false;
var mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
var mousePosition = new THREE.Vector3();
var raycaster = new THREE.Raycaster();

function init() {
  conf = {
    opacity: 0.8
  };

  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 0.1, 1000);
  cameraCtrl = new THREE.OrbitControls(camera);
  cameraCtrl.autoRotate = true;
  cameraCtrl.autoRotateSpeed = 5;

  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  initScene();

  onWindowResize();
  window.addEventListener('resize', onWindowResize, false);

  animate();
};

function initScene() {
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x000000);

  camera.position.z = 30;
  camera.position.y = 20;
  camera.lookAt(0, 0, 0);

  spriteMap = new THREE.Texture();
  var bubble = new Image();
  bubble.src = "";
  bubble.onload = function () {
    spriteMap.image = bubble;
    spriteMap.needsUpdate = true;
  };

  objects = [];
  for (var i = 0; i < nbObjects; i++) {
    var object = new Truc();
    objects.push(object);
    scene.add(object.sprite);
  }
}

function animate() {
  requestAnimationFrame(animate);

  cameraCtrl.update();

  renderer.render(scene, camera);
};

function Truc() {
  this.init();
  this.shuffle();
}

Truc.prototype.init = function () {
  this.material = new THREE.SpriteMaterial({
    color: randomColor({ luminosity: 'light' }),
    map: spriteMap,
    transparent: true,
    opacity: 1,
    depthTest: false,
    depthWrite: false,
    blending: THREE.AdditiveBlending
  });
  this.sprite = new THREE.Sprite(this.material);
};

Truc.prototype.shuffle = function () {
  this.scale1 = 0.1;
  this.scale2 = 2 + rnd(3);
  this.sprite.scale.set(this.scale1, this.scale1, 1);

  var rndv = getRandomVec3();
  this.sprite.position.set(rndv.x, rndv.y, rndv.z).multiplyScalar(50);
  this.sprite.position.y -= 25;

  this.material.opacity = conf.opacity;

  this.tt = this.scale2;
  TweenMax.to(this.sprite.scale, 1, { x: this.scale2, y: this.scale2, ease: Power2.easeIn });
  TweenMax.to(this.sprite.position, this.scale2, { y: this.sprite.position.y + 100, ease: Power2.easeIn });

  this.t1 = 1;
  TweenMax.to(this.sprite.position, this.t1, {
    x: this.sprite.position.x + rnd(10, true),
    z: this.sprite.position.z + rnd(10, true),
    ease:Linear.ease,
    repeat: Math.floor((this.tt/this.t1)/2),
    yoyo: true
  });

  TweenMax.to(this.material, 1, {
    opacity: 0,
    delay: this.tt-1,
    ease: Power2.easeIn,
    onCompleteParams: [this],
    onComplete: function (o) {
      o.shuffle();
    }
  });
};

function getRandomVec3() {
  const u = Math.random();
  const v = Math.random();
  const theta = u * 2.0 * Math.PI;
  const phi = Math.acos(2.0 * v - 1.0);
  const r = Math.cbrt(Math.random());
  const sinTheta = Math.sin(theta);
  const cosTheta = Math.cos(theta);
  const sinPhi = Math.sin(phi);
  const cosPhi = Math.cos(phi);
  const x = r * sinPhi * cosTheta;
  const y = r * sinPhi * sinTheta;
  const z = r * cosPhi;
  return { x: x, y: y, z: z };
}

function rnd(max, negative) {
  return negative ? Math.random() * 2 * max - max : Math.random() * max;
}

function onWindowResize() {
  whw = window.innerWidth / 2;
  whh = window.innerHeight / 2;
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

init();